//
//  ChartWeekViewModel.swift
//  KoiAccounting
//
//  Created by 纪洪文 on 05.04.25.
//

import Foundation
import SwiftUI

class ChartDateViewModel : KoiAccountingBaseViewModel {
    
    // 总金额
    @Published var totalAmount = 0.0
    // 平均值
    @Published var averageAmount = 0.0
    // 趋势数据
    @Published var trendData = [(day:String, amount:Double)]()
    // 饼图数据
    @Published var pieData = [ChartPieItem]()
    // 兼容 ios 16 的饼图
    @Published var koiPieData = [(value:Double, color:Color)]()
    // 类别金额汇总数据
    @Published var categoryAmountList = [CategoryAmount]()
    
    // 放在这里能比放在 view 里更持久
    var category: AccountingCategory? = nil
    
    let detailRepo = DetailRepo()
    
    let detailDao = KoiAccountingDB.standard.getDetailDao()
    
    func loadData(date: Date, categoryType: CategoryType, dateType: DateSelectType) {
        switch dateType {
        case .week:
            loadWeekData(date: date, categoryType: categoryType)
        case .month:
            loadMonthData(date: date, categoryType: categoryType)
        case .year:
            loadYearData(date: date, categoryType: categoryType)
        }
    }
    
    private func getTrendData(days: Array<String>, detailList: Array<AccountingDetailCombineView>, showDay:(String)->String) -> [(day:String, amount:Double)] {
        // 按日期分组
        var detailMap = [String: Array<AccountingDetailCombineView>]()
        var trendData = [(day:String, amount:Double)]()
        detailList.forEach { detail in
            let day = detail.dateGroupFormat.orEmpty
            if detailMap.contains(where: {key, value in key == day}) {
                detailMap[day]?.append(detail)
            } else {
                detailMap[day] = Array<AccountingDetailCombineView>()
                detailMap[day]?.append(detail)
            }
        }
        days.forEach { day in
            var amount = 0.0
            detailMap[day]?.forEach { detail in
                amount = amount + (detail.amount ?? 0.0)
            }
            trendData.append((day:showDay(day), amount:amount))
        }
        return trendData
    }
    
    func loadWeekData(date: Date, categoryType: CategoryType) {
        asyncBackground {
            let weekDays = date.toWeekDays()
            // 获取周支出/收入总额
            let amountTotal = self.fetchWeekAmountTotal(weekDays: weekDays, categoryType: categoryType)
            // 计算周平均值
            // 与今天比较
            let now = Date()
            // 一周7天
            var thisDay = 7
            if DateUtils.inThisWeek(weekDays: weekDays, date: now) {
                thisDay = now.dayOfWeek()
            }
            // 周平均值
            let weekAverage = amountTotal / Double(thisDay)
            // 获取趋势视图数据
            var trendData = [(day:String, amount:Double)]()
            let dayAmountMap = self.fetchWeekDayAmount(weekDays: weekDays, categoryType: categoryType)
            weekDays.forEach { day in
                let showDay = DateUtils.weekdayAbbr(from: day) ?? ""
                if let dayAmount = dayAmountMap[day] {
                    trendData.append((day:showDay, amount:dayAmount))
                } else {
                    trendData.append((day:showDay, amount:0.0))
                }
            }
            // 获取类别统计数据
            var categoryAmountList = self.fetchPieDataByWeekDays(weekDays: weekDays, categoryType: categoryType)
            
            var pieDataList = [ChartPieItem]()
            if (categoryAmountList.isEmpty) {
                // 显示空数据
                pieDataList.append(ChartPieItem(category: AccountingCategory(name:""), amount: 0, percent: 1, color: Color.gray))
            } else {
                // 转换饼图数据
                
                // 用于进行精度计算
                let handler = NSDecimalNumberHandler(
                    roundingMode: .plain,
                    scale: 3,  // 设置保留的小数位数
                    raiseOnExactness: false,
                    raiseOnOverflow: false,
                    raiseOnUnderflow: false,
                    raiseOnDivideByZero: false
                )
                for (i,_) in categoryAmountList.enumerated() {
                    let categoryAmount = categoryAmountList[i]
                    let amount = categoryAmount.amount
                    let percent = NSDecimalNumber(value: amount).dividing(by: NSDecimalNumber(value: amountTotal))
                        .rounding(accordingToBehavior: handler).doubleValue
                    categoryAmountList[i].percent = percent
                    if i < 5 {
                        let pieItem = ChartPieItem(category: categoryAmount.category, amount: amount, percent: percent, color: ChartPieColors.colors[i])
                        pieDataList.append(pieItem)
                    } else if i == 5 {
                        let pieItem = ChartPieItem(category: AccountingCategory(name:"其他"), amount: categoryAmount.amount, percent: percent, color: ChartPieColors.colors[i])
                        pieDataList.append(pieItem)
                    } else {
                        let count = pieDataList.count
                        pieDataList[count - 1].amount = pieDataList[count - 1].amount + categoryAmount.amount
                        pieDataList[count - 1].percent = NSDecimalNumber(value: (pieDataList[count - 1].amount)).dividing(by: NSDecimalNumber(value:amountTotal)).rounding(accordingToBehavior: handler).doubleValue
                    }
                }
            }

            // 更新界面数据
            self.asyncMain {
                self.totalAmount = amountTotal
                self.averageAmount = weekAverage
                self.trendData = trendData
                self.categoryAmountList = categoryAmountList
                self.pieData = pieDataList
                self.koiPieData = pieDataList.map{ data in (value:data.percent, color:data.color)}
            }
        }
    }
    
    func loadMonthData(date: Date, categoryType: CategoryType) {
        asyncBackground {
            let month = date.toYearMonth()
            let amountTotal = self.fetchMonthAmountTotal(month: month, categoryType: categoryType)
            
            var thisDay = date.monthMaxDays()
            if DateUtils.inThisMonth(data: date) {
                thisDay = date.dayOfMonth()
            }
            // 周平均值
            let monthAverage = amountTotal / Double(thisDay)
            // 获取趋势视图数据
            let dayAmountMap = self.fetchMonthDayAmount(month: month, categoryType: categoryType)
            // 获取当前月的全部日期
            var trendData = [(day:String, amount:Double)]()
            date.monthDays().forEach { day in
                let showDay = DateUtils.monthDayAbbr(from: day) ?? ""
                if let dayAmount = dayAmountMap[day] {
                    trendData.append((day:showDay, amount:dayAmount))
                } else {
                    trendData.append((day:showDay, amount:0.0))
                }
            }
            
            // 获取类别统计数据
            var categoryAmountList = self.fetchPieDataByMonth(month: month, categoryType: categoryType)
            // 转换饼图数据
            var pieDataList = [ChartPieItem]()
            if (categoryAmountList.isEmpty) {
                pieDataList.append(ChartPieItem(category: AccountingCategory(name:""), amount: 0, percent: 1, color: Color.gray))
            } else {
                // 用于进行精度计算
                let handler = NSDecimalNumberHandler(
                    roundingMode: .plain,
                    scale: 3,  // 设置保留的小数位数
                    raiseOnExactness: false,
                    raiseOnOverflow: false,
                    raiseOnUnderflow: false,
                    raiseOnDivideByZero: false
                )
                for (i,_) in categoryAmountList.enumerated() {
                    let categoryAmount = categoryAmountList[i]
                    let amount = categoryAmount.amount
                    let percent = NSDecimalNumber(value: amount).dividing(by: NSDecimalNumber(value: amountTotal))
                        .rounding(accordingToBehavior: handler).doubleValue
                    categoryAmountList[i].percent = percent
                    if i < 5 {
                        let pieItem = ChartPieItem(category: categoryAmount.category, amount: amount, percent: percent, color: ChartPieColors.colors[i])
                        pieDataList.append(pieItem)
                    } else if i == 5 {
                        let pieItem = ChartPieItem(category: AccountingCategory(name:"其他"), amount: categoryAmount.amount, percent: percent, color: ChartPieColors.colors[i])
                        pieDataList.append(pieItem)
                    } else {
                        let count = pieDataList.count
                        pieDataList[count - 1].amount = pieDataList[count - 1].amount + categoryAmount.amount
                        pieDataList[count - 1].percent = NSDecimalNumber(value: (pieDataList[count - 1].amount)).dividing(by: NSDecimalNumber(value:amountTotal)).rounding(accordingToBehavior: handler).doubleValue
                    }
                }
                
            }
            
            
            // 更新界面数据
            self.asyncMain {
                self.totalAmount = amountTotal
                self.averageAmount = monthAverage
                self.trendData = trendData
                self.categoryAmountList = categoryAmountList
                self.pieData = pieDataList
                self.koiPieData = pieDataList.map{ data in (value:data.percent, color:data.color)}
            }
        }
    }
    
    func loadYearData(date: Date, categoryType: CategoryType) {
        asyncBackground {
            let year = date.toYear()
            let amountTotal = self.fetchYearAmountTotal(year: year, categoryType: categoryType)
            
            var thisDay = 12
            if DateUtils.inThisYear(data: date) {
                thisDay = date.monthOfYear()
            }
            // 周平均值
            let amountAverage = amountTotal / Double(thisDay)
            // 获取趋势视图数据
            let dayAmountMap = self.fetchYearDayAmount(year: year, categoryType: categoryType)
            var trendData = [(day:String, amount:Double)]()

            for (i, day) in date.yearMonths().enumerated() {
                let showDay = "\(i+1)"
                if let dayAmount = dayAmountMap[day] {
                    trendData.append((day:showDay, amount:dayAmount))
                } else {
                    trendData.append((day:showDay, amount:0.0))
                }
            }
            
            // 获取类别统计数据
            var categoryAmountList = self.fetchPieDataByYear(year: year, categoryType: categoryType)
            
            // 转换饼图数据
            var pieDataList = [ChartPieItem]()
            
            if categoryAmountList.isEmpty {
                pieDataList.append(ChartPieItem(category: AccountingCategory(name:""), amount: 0, percent: 1, color: Color.gray))
            } else {
                // 用于进行精度计算
                let handler = NSDecimalNumberHandler(
                    roundingMode: .plain,
                    scale: 3,  // 设置保留的小数位数
                    raiseOnExactness: false,
                    raiseOnOverflow: false,
                    raiseOnUnderflow: false,
                    raiseOnDivideByZero: false
                )
                for (i,_) in categoryAmountList.enumerated() {
                    let categoryAmount = categoryAmountList[i]
                    let amount = categoryAmount.amount
                    let percent = NSDecimalNumber(value: amount).dividing(by: NSDecimalNumber(value: amountTotal))
                        .rounding(accordingToBehavior: handler).doubleValue
                    categoryAmountList[i].percent = percent
                    if i < 5 {
                        let pieItem = ChartPieItem(category: categoryAmount.category, amount: amount, percent: percent, color: ChartPieColors.colors[i])
                        pieDataList.append(pieItem)
                    } else if i == 5 {
                        let pieItem = ChartPieItem(category: AccountingCategory(name:"其他"), amount: categoryAmount.amount, percent: percent, color: ChartPieColors.colors[i])
                        pieDataList.append(pieItem)
                    } else {
                        let count = pieDataList.count
                        pieDataList[count - 1].amount = pieDataList[count - 1].amount + categoryAmount.amount
                        pieDataList[count - 1].percent = NSDecimalNumber(value: (pieDataList[count - 1].amount)).dividing(by: NSDecimalNumber(value:amountTotal)).rounding(accordingToBehavior: handler).doubleValue
                    }
                }
            }
            
            
            // 更新界面数据
            self.asyncMain {
                self.totalAmount = amountTotal
                self.averageAmount = amountAverage
                self.trendData = trendData
                self.categoryAmountList = categoryAmountList
                self.pieData = pieDataList
                self.koiPieData = pieDataList.map{ data in (value:data.percent, color:data.color)}
            }
        }
    }
    
    func fetchWeekAmountTotal (weekDays: Array<String>, categoryType: CategoryType) -> Double {
        return self.detailDao.getWeekTotalAmount(
            weekDays: weekDays,
            categoryType: categoryType.rawValue,
            uid: self.uid,
            bookId: self.bookId
        )
    }
    
    func fetchMonthAmountTotal (month: String, categoryType: CategoryType) -> Double {
        return self.detailDao.getMonthTotalAmount(
            month: month,
            categoryType: categoryType.rawValue,
            uid: self.uid,
            bookId: self.bookId
        )
    }
    
    func fetchYearAmountTotal (year: String, categoryType: CategoryType) -> Double {
        return self.detailDao.getYearTotalAmount(
            year: year,
            categoryType: categoryType.rawValue,
            uid: self.uid,
            bookId: self.bookId
        )
    }
    
    func fetchWeekDayAmount(weekDays: Array<String>, categoryType: CategoryType) -> [String : Double] {
        return self.detailDao.getDayAmountByWeekDays(
            weekDays: weekDays,
            categoryType: categoryType.rawValue,
            uid: self.uid,
            bookId: self.bookId
        )
    }
    
    func fetchMonthDayAmount(month: String, categoryType: CategoryType) -> [String : Double] {
        return self.detailDao.getDayAmountByMonth(
            month: month,
            categoryType: categoryType.rawValue,
            uid: self.uid,
            bookId: self.bookId
        )
    }
    
    func fetchYearDayAmount(year: String, categoryType: CategoryType) -> [String : Double] {
        return self.detailDao.getDayAmountByYear(
            year: year,
            categoryType: categoryType.rawValue,
            uid: self.uid,
            bookId: self.bookId
        )
    }
    
    func fetchPieDataByWeekDays(weekDays: Array<String>, categoryType: CategoryType) -> [CategoryAmount] {
        return self.detailRepo.getPieDataByWeekDays(
            weekDays: weekDays,
            categoryType: categoryType.rawValue,
            uid: uid,
            bookId: bookId
        )
    }
    
    func fetchPieDataByMonth(month: String, categoryType: CategoryType) -> [CategoryAmount] {
        return self.detailRepo.getPieDataByMonth(
            month: month,
            categoryType: categoryType.rawValue,
            uid: uid,
            bookId: bookId
        )
    }
    
    func fetchPieDataByYear(year: String, categoryType: CategoryType) -> [CategoryAmount] {
        return self.detailRepo.getPieDataByYear(
            year: year,
            categoryType: categoryType.rawValue,
            uid: uid,
            bookId: bookId
        )
    }
}
